package com.test.jogl;

import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLJPanel;

import com.sun.opengl.util.Animator;

//import static 

public class Board2 implements GLEventListener, MouseListener, MouseMotionListener {


   private static final double RAYON_NEUTRE = 1.0;
   private static final double RAYON_INTERNE = (0.5 / Math.tan(Math.toRadians(30.0))) * RAYON_NEUTRE;
   
   private static int NB_CLICK = 0;
   
   private static final int MAP_SIZE  = 7;
   private static final float EDGE_SIZE = 0.5F;
   
   private static boolean color = true;
   
   private float view_rotx = 0.0f, view_roty = 0.0f, view_rotz = 0.0f;
   
   private List<Integer> listHex;

   /**
    * @param args
    */
   public static void main(String[] args) {
      Frame frame = new Frame("Settlers of Catan");
      GLCanvas canvas = new GLCanvas();

      canvas.addGLEventListener(new Board2());
      frame.add(canvas);
      frame.setSize(900, 900);
      final Animator animator = new Animator(canvas);
      frame.addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
            // Run this on another thread than the AWT event queue to
            // make sure the call to Animator.stop() completes before
            // exiting
            new Thread(new Runnable() {
               public void run() {
                  animator.stop();
                  System.exit(0);
               }
            }).start();
         }
      });
      frame.setVisible(true);
      animator.start();
   }
   
   private boolean nextColor() {
      color = !color;
      return color;
   }

   private int prevMouseX, prevMouseY;

   private boolean mouseRButtonDown = false;

   public void init(GLAutoDrawable drawable) {
      // Use debug pipeline
      // drawable.setGL(new DebugGL(drawable.getGL()));

      List<Point2D.Float> list2D = generateMap(MAP_SIZE);
      GL gl = drawable.getGL();

      System.err.println("INIT GL IS: " + gl.getClass().getName());

      System.err.println("Chosen GLCapabilities: "
            + drawable.getChosenGLCapabilities());

      gl.setSwapInterval(1);

      float pos[] = { 5.0f, 5.0f, 10.0f, 0.0f };
      float red[] = { 0.8f, 0.1f, 0.0f, 1.0f };
      float green[] = { 0.0f, 0.9f, 0.2f, 1.0f };
      float blue[] = { 0.2f, 0.2f, 1.0f, 1.0f };

      gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, pos, 0);
      gl.glEnable(GL.GL_CULL_FACE);
      gl.glEnable(GL.GL_LIGHTING);
      gl.glEnable(GL.GL_LIGHT0);
      gl.glEnable(GL.GL_DEPTH_TEST);

      
      int c = 0;
      listHex = new ArrayList<Integer>();
      for (Point2D.Float currentPos : list2D) {
         currentPos = list2D.get(c);
         System.out.println("Case #" + (c+1));
         listHex.add(gl.glGenLists(1));
         gl.glNewList(listHex.get(c), GL.GL_COMPILE);
         if(c < (MAP_SIZE - 2) * 6) {
            gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT_AND_DIFFUSE, blue, 0);
         }
         else {
            gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT_AND_DIFFUSE, nextColor() ? red : green, 0);
         }
         gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT_AND_DIFFUSE);
         
         hexagon(gl, currentPos.x * EDGE_SIZE, currentPos.y * EDGE_SIZE, EDGE_SIZE);
         gl.glEndList();
         c++;
      }
      
      gl.glEnable(GL.GL_NORMALIZE);

      drawable.addMouseListener(this);
      drawable.addMouseMotionListener(this);
   }

   public void display(GLAutoDrawable drawable) {
      GL gl = drawable.getGL();
      if ((drawable instanceof GLJPanel) && !((GLJPanel) drawable).isOpaque()
            && ((GLJPanel) drawable).shouldPreserveColorBufferIfTranslucent()) {
         gl.glClear(GL.GL_DEPTH_BUFFER_BIT);
      } else {
         gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
      }

      gl.glPushMatrix();
      gl.glRotatef(view_rotx, 1.0f, 0.0f, 0.0f);
      gl.glRotatef(view_roty, 0.0f, 1.0f, 0.0f);
      gl.glRotatef(view_rotz, 0.0f, 0.0f, 1.0f);

      gl.glPushMatrix();
      gl.glTranslatef(-3.0f, 2.0f, 0.0f);
      // gl.glRotatef(angle, 0.0f, 0.0f, 1.0f);
      
      if(true) {
         for (Integer hex : listHex) {
            gl.glCallList(hex);
         }
      }
      else {
         int hex;
         int c = 0;
         for (Iterator<Integer> iterator = listHex.iterator(); iterator.hasNext();) {
            hex = iterator.next();
            if(NB_CLICK > c) {
               gl.glCallList(hex);
               c++;
            }
         }
      }
      gl.glPopMatrix();
   }

   public void displayChanged(GLAutoDrawable drawable, boolean modeChanged,
         boolean deviceChanged) {
   }

   public static void hexagon(GL gl, float initX, float initY, float edge) {

      float x1, y1;
      float x2, y2;
      float x3, y3;
      float x4, y4;
      float x5, y5;
      float x6, y6;
      float z = 0.0f;
      gl.glShadeModel(GL.GL_FLAT);
      gl.glNormal3f(0.0f, 0.0f, 1.0f);

      gl.glBegin(GL.GL_POLYGON);
      x1 = initX - edge * 0.5F;
      y1 = initY - (float)RAYON_INTERNE * edge;
      gl.glVertex3f(x1, y1, z);
      System.out.println("x1: " + x1 + "\ty1: " + y1);

      x2 = x1 + edge;
      y2 = y1;
      gl.glVertex3f(x2, y2, z);
      System.out.println("x2: " + x2 + "\ty2: " + y2);

      x3 = x2 + 0.5F * edge;
      y3 = y2 + (float)RAYON_INTERNE * edge;
      gl.glVertex3f(x3, y3, z);
      System.out.println("x3: " + x3 + "\ty3: " + y3);

      x4 = x2;
      y4 = y3 + (float)RAYON_INTERNE * edge;
      gl.glVertex3f(x4, y4, z);
      System.out.println("x4: " + x4 + "\ty4: " + y4);

      x5 = x1;
      y5 = y4;
      gl.glVertex3f(x5, y5, z);
      System.out.println("x5: " + x5 + "\ty5: " + y5);

      x6 = x1 - (x3 - x2);
      y6 = y3;
      gl.glVertex3f(x6, y6, z);
      System.out.println("x6: " + x6 + "\ty6: " + y6 + "\n");
      gl.glEnd();
   }

   
   // Methods required for the implementation of MouseListener
   public void mouseEntered(MouseEvent e) {
   }

   public void mouseExited(MouseEvent e) {
   }

   public void mousePressed(MouseEvent e) {
      prevMouseX = e.getX();
      prevMouseY = e.getY();
      if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
         mouseRButtonDown = true;
      }
   }

   public void mouseReleased(MouseEvent e) {
      if ((e.getModifiers() & e.BUTTON3_MASK) != 0) {
         mouseRButtonDown = false;
      }
   }

   public void mouseClicked(MouseEvent e) {
      NB_CLICK++;
   }

   // Methods required for the implementation of MouseMotionListener
   public void mouseDragged(MouseEvent e) {
      int x = e.getX();
      int y = e.getY();
      Dimension size = e.getComponent().getSize();

      float thetaY = 360.0f * ((float) (x - prevMouseX) / (float) size.width);
      float thetaX = 360.0f * ((float) (prevMouseY - y) / (float) size.height);

      prevMouseX = x;
      prevMouseY = y;

      view_rotx += thetaX;
      view_roty += thetaY;
   }

   public void mouseMoved(MouseEvent e) {
   }

   public void reshape(GLAutoDrawable drawable, int x, int y, int width,
         int height) {
      GL gl = drawable.getGL();

      float h = (float) height / (float) width;

      gl.glMatrixMode(GL.GL_PROJECTION);

      System.err.println("GL_VENDOR: " + gl.glGetString(GL.GL_VENDOR));
      System.err.println("GL_RENDERER: " + gl.glGetString(GL.GL_RENDERER));
      System.err.println("GL_VERSION: " + gl.glGetString(GL.GL_VERSION));
      gl.glLoadIdentity();
      gl.glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f);
      gl.glMatrixMode(GL.GL_MODELVIEW);
      gl.glLoadIdentity();
      gl.glTranslatef(0.0f, 0.0f, -40.0f);
   }

   public static List<Point2D.Float> generateMap(int size) {
      List<Point2D.Float> lst = new ArrayList<Point2D.Float>();

      Point2D.Float currentPos = new Point2D.Float(0F, 0F);
      int length = size - 2;
      while(length != 0) {
         downLine(currentPos, length, lst);
         downRightLine(currentPos, length, lst);
         upRightLine(currentPos, length, lst);
         upLine(currentPos, length, lst);
         upLeftLine(currentPos, length, lst);
         downLeftLine(currentPos, length, lst);
         currentPos.setLocation(currentPos.getX() + 1.5 * RAYON_NEUTRE, currentPos.getY() - 1 * RAYON_INTERNE);
         length--;
      }
      lst.add((Point2D.Float)currentPos.clone());

      int i = 1;
      for (Point2D.Float p2D : lst) {
         System.out.println(i + ". " +  p2D.toString());
         i++;
      }

      return lst;
   }
   private static void downLine(Point2D.Float currentPos, int length, List<Point2D.Float> lst) {
      line(currentPos, +0.0 * RAYON_NEUTRE, -2 * RAYON_INTERNE, length, lst);
   }
   private static void downRightLine(Point2D.Float currentPos, int length, List<Point2D.Float> lst) {
      line(currentPos, +1.5 * RAYON_NEUTRE, -1 * RAYON_INTERNE, length, lst);
   }
   private static void upRightLine(Point2D.Float currentPos, int length, List<Point2D.Float> lst) {
      line(currentPos, +1.5 * RAYON_NEUTRE, +1 * RAYON_INTERNE, length, lst);
   }
   private static void upLine(Point2D.Float currentPos, int length, List<Point2D.Float> lst) {
      line(currentPos, +0.0 * RAYON_NEUTRE, +2 * RAYON_INTERNE, length, lst);
   }
   private static void upLeftLine(Point2D.Float currentPos, int length, List<Point2D.Float> lst) {
      line(currentPos, -1.5 * RAYON_NEUTRE, +1 * RAYON_INTERNE, length, lst);
   }
   private static void downLeftLine(Point2D.Float currentPos, int length, List<Point2D.Float> lst) {
      line(currentPos, -1.5 * RAYON_NEUTRE, -1 * RAYON_INTERNE, length, lst);
   }
   private static void line(Point2D.Float currentPos, double x, double y, int length, List<Point2D.Float> lst) {
      for (int i = 0; i < length; i++) {
         currentPos.setLocation(currentPos.getX() + x, currentPos.getY() + y);
         lst.add((Point2D.Float)currentPos.clone());
      }
   }
}
